﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
namespace DataBase
{
    public class TestDataBase : DbContext
    {
        public TestDataBase()
            : base("default_db")
        {
            new initialize_DataBase();
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            initialize_DataBase.InitFelids(modelBuilder, this);
            base.OnModelCreating(modelBuilder);
        }
        public DbSet<Char_Test> Char_Test { get; set; }
    }
    class initialize_DataBase
    {
        private static Config_DataBase _initializer;
        private static object _initializerLock = new object();
        private static bool _isInitialized;
        public initialize_DataBase()
        {
            LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
        }

        class Config_DataBase
        {
            public Config_DataBase()
            {
                Database.SetInitializer<TestDataBase>(new Config_DataBase_CreateDataBase());
                Database.SetInitializer<TestDataBase>(new Config_DataBase_InitData());
            }

            class Config_DataBase_CreateDataBase : CreateDatabaseIfNotExists<TestDataBase>
            {
                protected override void Seed(TestDataBase context)
                {
                    context.Database.CreateIfNotExists();
                }
            }

            class Config_DataBase_InitData : DropCreateDatabaseIfModelChanges<TestDataBase>
            {
                protected override void Seed(TestDataBase context)
                {
                    var entity = new List<Char_Test>();
                    entity.Add(new Char_Test() { Name = "我是测试数据" });
                    entity.ForEach(p =>
                    {
                        context.Char_Test.Add(p);
                    });
                    context.SaveChanges();
                }
            }
        }

        internal static void InitFelids(DbModelBuilder modelBuilder, DbContext dbContext)
        {
            var DbSet_Type = typeof(DbSet<>);
            var DataBaseDataType_Type = typeof(DataBase.Attributes.DataBaseDataType);
            var type = dbContext.GetType();
            foreach (var item in type.GetProperties())
            {
                //DbSet<T>
                var pT = item.PropertyType;
                if (pT.IsGenericType && pT.GetGenericTypeDefinition() == DbSet_Type)
                {
                    //DbSet_T 实体对象
                    var TType = pT.GetGenericArguments()[0];
                    foreach (var column in TType.GetProperties())
                    {
                        //实体对象 字段
                        if (column.IsDefined(DataBaseDataType_Type, true))
                        {
                            var attr = column.GetType().GetCustomAttributes(DataBaseDataType_Type, true)[0] as DataBase.Attributes.DataBaseDataType;
                            var bulidType = modelBuilder.GetType();
                            //modelBuilder.Entity<Char_Test>()
                            var EntityMethod = bulidType.GetMethod("Entity");
                            var EntityMethod_DataBaseDataType = EntityMethod.MakeGenericMethod(TType);
                            var EntityTypeConfiguration_DataBaseDataType = EntityMethod_DataBaseDataType.Invoke(modelBuilder, null);
                            var EntityTypeConfiguration_DataBaseDataType_Type = EntityTypeConfiguration_DataBaseDataType.GetType();
                            //.Property(p => p.Name)
                            //p => p.Name
                            var Expression_Parameter = Expression.Parameter(TType, "TType");//p=>
                            var Expression_body = Expression.MakeMemberAccess(Expression_Parameter, column);//p.Name
                            var Expression_lambda = Expression.Lambda(Expression_body, Expression_Parameter);//p=>p.Name
                            //.Property
                            var Property_Method = EntityTypeConfiguration_DataBaseDataType_Type.GetMethod("Property", new Type[] { Expression_lambda.GetType() });
                            var PropertyConfiguration = Property_Method.Invoke(EntityTypeConfiguration_DataBaseDataType, new object[] { Expression_lambda });
                            var PropertyConfiguration_Type = PropertyConfiguration.GetType();

                            switch (attr.SqlDbType)
                            {
                                case System.Data.SqlDbType.Char:
                                    if (attr.Length != null)
                                    {
                                        PropertyConfiguration_Type.InvokeMember("IsUnicode", BindingFlags.InvokeMethod, null, PropertyConfiguration, new object[] { false });
                                        PropertyConfiguration_Type.InvokeMember("IsFixedLength", BindingFlags.InvokeMethod, null, PropertyConfiguration, null);
                                        PropertyConfiguration_Type.InvokeMember("HasMaxLength", BindingFlags.InvokeMethod, null, PropertyConfiguration, new object[] { attr.Length });
                                    }
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
            }
            //public StringPropertyConfiguration 
            //Property(Expression<Func<TStructuralType, string>> propertyExpression);
            var x = modelBuilder.Entity<Char_Test>();//EntityTypeConfiguration<TEntityType>
            //x.Property(p=>p.Decimal).HasPrecision
            //x.Property(p => p.Name).IsUnicode(false).IsFixedLength().HasMaxLength(120);
            //x.Property
            //x.Property(p=>p.Name).IsFixedLength().IsUnicode().HasMaxLength 
        }
    }
}
